package com.wrupple.muba.desktop.client.bootstrap.state.impl;

import java.util.ArrayList;
import java.util.Collection;

import com.google.gwt.core.client.GWT;
import com.google.gwt.event.shared.EventBus;
import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.rpc.ServiceDefTarget;
import com.google.inject.Inject;
import com.wrupple.muba.common.domain.RawSlice;
import com.wrupple.muba.common.domain.Slice;
import com.wrupple.muba.common.shared.StateTransition;
import com.wrupple.muba.desktop.client.bootstrap.state.LoadMissingSlices;
import com.wrupple.muba.desktop.domain.DesktopDescriptor;
import com.wrupple.muba.desktop.domain.DesktopLoadingStateHolder;
import com.wrupple.muba.desktop.shared.services.ConfigService;
import com.wrupple.muba.desktop.shared.services.ConfigServiceAsync;

public class LoadMissingSlicesImpl implements LoadMissingSlices {
	
	static class SliceCallback implements AsyncCallback<Slice>{
		
		RawSlice raw;
		Controller controller;
		
		public SliceCallback(RawSlice raw, Controller controller) {
			super();
			this.raw = raw;
			this.controller = controller;
		}

		@Override
		public void onFailure(Throwable caught) {
			controller.execute();
		}

		@Override
		public void onSuccess(Slice result) {
			raw.setSlice(result);
			result.setRawApp(raw);
			controller.end(raw);
		}
		
	}

	class Controller implements Command {
		private int count = 0;
		private StateTransition<DesktopLoadingStateHolder> end;
		private DesktopLoadingStateHolder parameter;
		private ArrayList<RawSlice> slices;

		public Controller(StateTransition<DesktopLoadingStateHolder> fin, DesktopLoadingStateHolder parameter) {
			super();
			this.slices = new ArrayList<RawSlice>();
			this.end = fin;
			this.parameter = parameter;
		}

		public void addSlice(RawSlice raw) {
			slices.add(raw);
		}

		public void execute() {
			GWT.log("Slice done");
			count++;
			if (slices.size() == 0 || count == slices.size()) {
				GWT.log("All Slices have been configured (or at least an attempt was made) Proceding...");
				parameter.setDesktopDescriptor(validator.validate(parameter.getDesktopDescriptor()));
				
				end.setResultAndFinish(parameter);
			}

		}

		public void end(RawSlice raw) {
			slices.remove(raw);
			execute();
		}

		public int getCount() {
			return slices.size();
		}

		public ArrayList<RawSlice> getSlices() {
			return this.slices;
		}

	}
	
	public interface DesktopValidator {
		DesktopDescriptor validate(DesktopDescriptor desktop);
	}
	
	DesktopValidator validator;
	
	
	@Inject
	public LoadMissingSlicesImpl(DesktopValidator validator) {
		super();
		this.validator = validator;
	}
	
	//FIXME use a ParallelProcess

	@Override
	public void start(DesktopLoadingStateHolder parameter, StateTransition<DesktopLoadingStateHolder> onDone,EventBus eventBus) {
		Controller callback = new Controller(onDone,parameter);
		Collection<RawSlice> collection =parameter.getDesktopDescriptor().getRawSlices();;
		
		for (RawSlice slice : collection ) {
			GWT.log("checking if " + slice.getDefaultName() + " has been initialized");
			if (slice.getSlice() == null ) {
				GWT.log(slice.getDefaultName() + " will be marked for initialization");
				callback.addSlice(slice);
			}
		}
		
		
		GWT.log(callback.getCount() + "slices are marked for initialization");
		if (callback.getCount() == 0) {
			GWT.log("no slices to initialize, proceding...");
			callback.end.setResultAndFinish(parameter);
		} else {
			GWT.log("Starting initialization process");
			for (RawSlice slice : callback.getSlices()) {
				configureRawSlice(slice,callback);
			}
		}
	}

	private void configureRawSlice(RawSlice raw,Controller controller) {
		
		// Se configura el punto de acceso RPC para responder a las
		// peticiones
		ServiceDefTarget endpoint;
		ConfigServiceAsync service = GWT.create(ConfigService.class);
		endpoint = (ServiceDefTarget) service;
		String strService = raw.getConfigurationURI();
		endpoint.setServiceEntryPoint(strService);
		
		AsyncCallback<Slice> callback = new SliceCallback(raw, controller);
		service.getSlice(callback);
	}
	
	
	private String asserURLisAbsolute(String url, String baseURL) {
		if (!isAbsolute(url)) {
			if (baseURL == null) {
				throw new IllegalArgumentException("Not enough parameters");
			}
			url = prependURL(url, baseURL);
		}
		return url;
	}
	
	private boolean isAbsolute(String url) {
		return url.length() >= 8 && (url.substring(0, 8)).matches("http(s)?://.");
	}
	
	private String prependURL(String href, String base) {
		if (href.charAt(0) == '/') {
			href = href.substring(1, href.length());
		}
		return base + href;
	}

}
